/*
 *  CS202 - Spring 2009">
 *  Professor: Dr. Michael Peterson">
 *  Student: Deylo Woo (dwoo711@gmail.com) ">
 */
package project_3_v_2;

import javax.swing.*;
import java.awt.*;
import java.util.LinkedList;

/**
 * Class JPanel: extends JPanel this Panel holds the game
 * @author deylo
 */
public class GamePanel extends JPanel {

    private Cannon _cannon;
    private LinkedList<Missile> _missiles;
    private LinkedList<Ship> _ships;
    private LinkedList<Explosion> _explosions;
    private int _score;

    /**
     * Constructor method, calls parents class contructor and initialize variables.
     */
    public GamePanel() {
        super();
        this.repaint();
        _missiles = new LinkedList<Missile>();
        _explosions = new LinkedList<Explosion>();

        this.setBackground(Color.BLUE);
        this.setVisible(true);
    }


    /**
     * Move method, this method is called when along with paint method to move ovbject xy pos.
     */
    public void move() {
        //move cannons
        if (_cannon == null) {
            _cannon = new Cannon((getWidth() / 2) - 10, getHeight()- 20, 20, 20, 0, 0, Color.RED);
        }
        _cannon.Move(getHeight(), getWidth());

        //Move all missiles
        for (int x = 0; x < _missiles.size(); x++) {
            Missile _msl = _missiles.get(x);
            _msl.Move(getHeight(), getWidth());
            if (CheckForOutOfBounds(_msl)) {
                _missiles.remove(x);
            }
        }

        //Move all space ships
        if (_ships == null) {
            _ships = new LinkedList<Ship>();
        }
        while(_ships.size() < 5){
            Ship _newShip = MakeShip();
            _ships.add(_newShip);
        }
        for (int x = 0; x < _ships.size(); x++) {
            Ship _shp = _ships.get(x);
            _shp.Move(getHeight(), getWidth());
            if (CheckForOutOfBounds(_shp)) {
                _ships.remove(x);
            }
        }

        //Explosion
        for(int x = 0; x < _explosions.size(); x++){
            Explosion _expl = _explosions.get(x);
            _expl.Move(getHeight(), getWidth());
            _expl.setTimer(_expl.getTimer() - 20);
            if(_expl.getTimer() <= 0){
                _explosions.remove(_expl);
            }
        }

        CheckForCollision();
    }
    /**
     * paints the object on screen
     * @param g: graphics to be painted
     */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());

        getCannon().paint(g);

        for (Missile _msl : _missiles) {
            _msl.paint(g);
        }

        for (Ship _shp : _ships) {
            _shp.paint(g);
        }

        for(Explosion _expl : _explosions){
            _expl.paint(g);
        }  
    }
    /**
     * This method checks if object are our of bounds within the JPanel
     * @param mvObj: the object to be checked
     * @return: true if obj is out of bounds.
     */
    public boolean CheckForOutOfBounds(MovingObject mvObj) {
        boolean isOuOfB = false;
        if (mvObj.getXCoord() < (0 - mvObj.getRun())) {
            isOuOfB = true;
        } else if (mvObj.getXCoord() > (getWidth() - mvObj.getWidth())) {
            isOuOfB = true;
        }
        if (mvObj.getYCoord() < (0 - mvObj.getRise())) {
            isOuOfB = true;
        } else if (mvObj.getYCoord() > (getHeight() - mvObj.getHeight())) {
            isOuOfB = true;
        }
        return isOuOfB;
    }
    /**
     * This method creats chips randomly in size, color, speed and position
     * @return: return the actual ship
     */
    public Ship MakeShip() {
        Color _Shipcolor = GetRandomColor();
        int _Shipheight = (int) ((Math.random() * 20) + 10); //range from 10-20
        int _Shipwidth = (int) ((Math.random() * 100) + 20);
        int _Shiprise = (int) 0;
        //int _Shiprun = (int) ((Math.random() * 7) + 2);
        //set speed based on size
        int _Shiprun = 10000/(_Shipheight * _Shipwidth);
        int _ShipyCoord = (int) (Math.random() * 500);
        int _ShipxCoord = 1;
        if (((int) ((Math.random() * 2) + 1) == 1)) {
            _ShipxCoord = 1;
        } else {
            _ShipxCoord = getWidth() - _Shipwidth;
            _Shiprun = -_Shiprun;
        }
        Ship _ship = new Ship(_ShipxCoord, _ShipyCoord, _Shipheight, _Shipwidth, _Shiprise, _Shiprun, _Shipcolor);
        _ship.setValue((_Shipheight * _Shipwidth)/10);
        
        return _ship;
    }
    /**
     * This method is generates random color
     * @return: return the color itself
     */
    private Color GetRandomColor() {
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        return new Color(red, green, blue);
    }

    /**
     * Checks if objects are colliding
     * @return: true if obj collided with any ogher object
     */
    public boolean CheckForCollision() {
        boolean _hasCollided = false;
        //iterate through all ships and missiles

        for (int x = 0; x < _missiles.size(); x++) {
            for (int y = 0; y < _ships.size(); y++) {
                Missile _msl = _missiles.get(x);
                Ship _shp = _ships.get(y);
                if (_msl != null && _shp != null) {
                    //check for x,y collision
                    if (_msl.getXCoord() >= _shp.getXCoord() &&
                            _msl.getXCoord() <= _shp.getXCoord() + _shp.getWidth() &&
                            _msl.getYCoord() >= _shp.getYCoord() &&
                            _msl.getYCoord() <= _shp.getYCoord() + _shp.getHeight()) {
                        _score += _shp.Value;
                        Explode(_msl.getXCoord(), _msl.getYCoord(), _shp.Value/5);
                        _ships.remove(_shp);
                        _missiles.remove(_msl);
                        _hasCollided = true;
                        break;
                    }
                }
            }
        }
        return _hasCollided;
    }
    /**
     * Creates explosion on screen
     * @param xCoord: x coordinate of explosion
     * @param yCoord: y coordinate of explosion
     * @param diamete: the diameter of the explosion, I use a % of the ship mass.
     */
    public void Explode(int xCoord, int yCoord, int diameter){
        Explosion _expl = new Explosion(xCoord, yCoord, diameter, diameter, 0, 0, Color.RED);
        _explosions.add(_expl);

    }

    /**
     *When key pressed, this method will create a missile on screen at the correct location.
     */
    public void FireMissile() {
        Missile _missile;
        _missile = new Missile(_cannon.getXCoord() + 10, _cannon.getYCoord(), 10, 3, -5, 0, Color.BLACK);
        _missiles.add(_missile);
    }

    /**
     * This method moves the cannon left on screen
     */
    public void MoveLeft() {
        if (_cannon.getXCoord() > 0) {
            _cannon.setXCoord(_cannon.getXCoord() - 5);
        }
    }

    /**
     * This method moves the cannon right on screen
     */
    public void MoveRight() {
        if (_cannon.getXCoord() < getWidth() - _cannon.getWidth()) {
            _cannon.setXCoord(_cannon.getXCoord() + 5);
        }
    }

    //Getter and Setter methods for all properties of this class

    /**
     * @return the _cannon
     */
    public MovingObject getCannon() {
        return _cannon;
    }

    /**
     * @param cannon the _cannon to set
     */
    public void setCannon(Cannon cannon) {
        this._cannon = cannon;
    }

    /**
     * @return the _score
     */
    public int getScore() {
        return _score;
    }

    /**
     * @param score the _score to set
     */
    public void setScore(int score) {
        this._score = score;
    }
}
